package com.ruoyi.business.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alipay.api.internal.util.AlipaySignature;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ijpay.alipay.AliPayApi;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.kit.HttpKit;
import com.ijpay.core.kit.WxPayKit;
import com.ruoyi.business.app.bo.AppMyOrderBo;
import com.ruoyi.business.app.vo.AppMyOrderVo;
import com.ruoyi.business.bo.HcxMerchantOrderAddBo;
import com.ruoyi.business.bo.HcxMerchantOrderEditBo;
import com.ruoyi.business.bo.HcxMerchantOrderQueryBo;
import com.ruoyi.business.domain.*;
import com.ruoyi.business.mapper.*;
import com.ruoyi.business.service.IHcxCarWashService;
import com.ruoyi.business.service.IHcxMerchantOrderService;
import com.ruoyi.business.service.IHcxOrderEvaluatePicsService;
import com.ruoyi.business.vo.HcxMerchantOrderVo;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
import com.ruoyi.common.core.page.PagePlus;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.CustomException;
import com.ruoyi.common.utils.AssertUtils;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.pay.entity.AliPayBean;
import com.ruoyi.pay.entity.UnionPayBean;
import com.ruoyi.pay.entity.WxPayV3Bean;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * 商家订单Service业务层处理
 *
 * @author wsdz
 * @date 2022-08-17
 */
@Service
@AllArgsConstructor
@Slf4j
public class HcxMerchantOrderServiceImpl extends ServicePlusImpl<HcxMerchantOrderMapper, HcxMerchantOrder> implements IHcxMerchantOrderService {


    private final IHcxOrderEvaluatePicsService orderEvaluatePicsService;

    private final HcxOrderEvaluateMapper hcxOrderEvaluateMapper;

    private final WxPayV3Bean wxPayV3Bean;

    private final HcxAppUserMapper hcxAppUserMapper;

    private final HcxWithdrawDetailMapper hcxWithdrawDetailMapper;

    private final AliPayBean aliPayBean;

    private final UnionPayBean unionPayBean;

    private final HcxUserCouponMapper hcxUserCouponMapper;

    private final HcxMerchantMapper hcxMerchantMapper;

    private final RedisCache redisCache;

    private final HcxPlatformProfitMapper hcxPlatformProfitMapper;


    private final HcxCarWashMapper hcxCarWashMapper;

    private final IHcxCarWashService hcxCarWashService;

    private final HcxPlatformUserMapper hcxPlatformUserMapper;


    @Override

    public HcxMerchantOrderVo queryById(Long id) {
        return getVoById(id, HcxMerchantOrderVo.class);
    }

    @Override
    public TableDataInfo<HcxMerchantOrderVo> queryPageList(HcxMerchantOrderQueryBo bo) {
        PagePlus<HcxMerchantOrder, HcxMerchantOrderVo> result = pageVo(PageUtils.buildPagePlus(), buildQueryWrapper(bo), HcxMerchantOrderVo.class);
        return PageUtils.buildDataInfo(result);
    }


    @Override
    public TableDataInfo<AppMyOrderVo> queryAppPageList(AppMyOrderBo bo) {
        PagePlus<HcxMerchantOrder, AppMyOrderVo> result = pageVo(PageUtils.buildPagePlus(), buildAppQueryWrapper(bo), AppMyOrderVo.class);
        return PageUtils.buildDataInfo(result);
    }


    @Override
    public List<HcxMerchantOrderVo> queryList(HcxMerchantOrderQueryBo bo) {
        return listVo(buildQueryWrapper(bo), HcxMerchantOrderVo.class);
    }

    private LambdaQueryWrapper<HcxMerchantOrder> buildQueryWrapper(HcxMerchantOrderQueryBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<HcxMerchantOrder> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getMerchantId() != null, HcxMerchantOrder::getMerchantId, bo.getMerchantId());
        lqw.like(StrUtil.isNotBlank(bo.getMerchantName()), HcxMerchantOrder::getMerchantName, bo.getMerchantName());
        lqw.eq(bo.getProductId() != null, HcxMerchantOrder::getProductId, bo.getProductId());
        lqw.like(StrUtil.isNotBlank(bo.getProductName()), HcxMerchantOrder::getProductName, bo.getProductName());
        lqw.eq(StrUtil.isNotBlank(bo.getPicUrl()), HcxMerchantOrder::getPicUrl, bo.getPicUrl());
        lqw.eq(StrUtil.isNotBlank(bo.getSummary()), HcxMerchantOrder::getSummary, bo.getSummary());
        lqw.eq(bo.getProPrice() != null, HcxMerchantOrder::getProPrice, bo.getProPrice());
        lqw.eq(bo.getProNum() != null, HcxMerchantOrder::getProNum, bo.getProNum());
        lqw.eq(bo.getShouldPrice() != null, HcxMerchantOrder::getShouldPrice, bo.getShouldPrice());
        lqw.eq(bo.getActualPrice() != null, HcxMerchantOrder::getActualPrice, bo.getActualPrice());
        lqw.eq(StrUtil.isNotBlank(bo.getOrderNum()), HcxMerchantOrder::getOrderNum, bo.getOrderNum());
        lqw.eq(bo.getUserCouponId() != null, HcxMerchantOrder::getUserCouponId, bo.getUserCouponId());
        lqw.eq(bo.getDenomination() != null, HcxMerchantOrder::getDenomination, bo.getDenomination());
        lqw.eq(StrUtil.isNotBlank(bo.getStatus()), HcxMerchantOrder::getStatus, bo.getStatus());
        lqw.eq(StrUtil.isNotBlank(bo.getCalcelReason()), HcxMerchantOrder::getCalcelReason, bo.getCalcelReason());
        lqw.eq(bo.getWashTimes() != null, HcxMerchantOrder::getWashTimes, bo.getWashTimes());
        lqw.eq(bo.getSurplusTimes() != null, HcxMerchantOrder::getSurplusTimes, bo.getSurplusTimes());
        lqw.eq(StrUtil.isNotBlank(bo.getOrderType()), HcxMerchantOrder::getOrderType, bo.getOrderType());
        lqw.eq(StrUtil.isNotBlank(bo.getPayType()), HcxMerchantOrder::getPayType, bo.getPayType());
        lqw.eq(StrUtil.isNotBlank(bo.getHexiaoCode()), HcxMerchantOrder::getHexiaoCode, bo.getHexiaoCode());
        lqw.eq(StrUtil.isNotBlank(bo.getDelFlag()), HcxMerchantOrder::getDelFlag, bo.getDelFlag());
        lqw.orderByDesc(HcxMerchantOrder::getCreateTime);
        return lqw;
    }

    private LambdaQueryWrapper<HcxMerchantOrder> buildAppQueryWrapper(AppMyOrderBo bo) {
        LambdaQueryWrapper<HcxMerchantOrder> lqw = Wrappers.lambdaQuery();
        lqw.eq(HcxMerchantOrder::getUserId, SecurityUtils.getUserId());
        lqw.eq(StrUtil.isNotBlank(bo.getStatus()), HcxMerchantOrder::getStatus, bo.getStatus());
        lqw.eq(HcxMerchantOrder::getOrderType, 0);
        lqw.orderByDesc(HcxMerchantOrder::getCreateTime);
        return lqw;
    }


    @Override
    public Boolean insertByAddBo(HcxMerchantOrderAddBo bo) {
        HcxMerchantOrder add = BeanUtil.toBean(bo, HcxMerchantOrder.class);
        validEntityBeforeSave(add);
        return save(add);
    }

    @Override
    public Boolean updateByEditBo(HcxMerchantOrderEditBo bo) {
        HcxMerchantOrder update = BeanUtil.toBean(bo, HcxMerchantOrder.class);
        validEntityBeforeSave(update);
        return updateById(update);
    }

    /**
     * 保存前的数据校验
     *
     * @param entity 实体类数据
     */
    private void validEntityBeforeSave(HcxMerchantOrder entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return removeByIds(ids);
    }

    @Override
    public String importHcxMerchantOrder(List<HcxMerchantOrderVo> hcxMerchantOrderList) {
        AssertUtils.isTrue(CollectionUtils.isNotEmpty(hcxMerchantOrderList), "导入数据不能为空");
        int successNum = 0;
        for (HcxMerchantOrderVo hcxMerchantOrder : hcxMerchantOrderList) {
            HcxMerchantOrder add = BeanUtil.toBean(hcxMerchantOrder, HcxMerchantOrder.class);
            save(add);
            successNum++;
        }
        String msg = String.format("导入完成，共计 %d 条数据，成功 %d 条！", hcxMerchantOrderList.size(), successNum);
        if (successNum != hcxMerchantOrderList.size()) {
            msg = msg + String.format("失败 %d 条！", hcxMerchantOrderList.size() - successNum);
        }
        return msg;
    }


    @Override
    @Transactional
    public Boolean deleteMyorder(Long orderId) {
        // 删除订单的评价数据的照片
        boolean result;
        result = orderEvaluatePicsService.remove(new LambdaQueryWrapper<HcxOrderEvaluatePics>().eq(HcxOrderEvaluatePics::getOrderId, orderId));
        // 删除订单评价数据
        result = hcxOrderEvaluateMapper.delete(new LambdaQueryWrapper<HcxOrderEvaluate>().eq(HcxOrderEvaluate::getOrderId, orderId)) > 0;
        // 删除订单
        result = removeById(orderId);
        return result;
    }

    @Override
    @Transactional
    public Boolean checkOrder(String orderNum) {
        HcxMerchantOrder hcxMerchantOrder = getOne(new LambdaQueryWrapper<HcxMerchantOrder>().eq(HcxMerchantOrder::getOrderNum, orderNum));
        if (hcxMerchantOrder.getSurplusTimes() == 0) {
            throw new CustomException("核销失败,已无使用次数");
        }
        // 如果是单次洗车 则状态修改为已使用(待评价)
        if (Constants.ZERO.equals(hcxMerchantOrder.getOrderType())) {
            hcxMerchantOrder.setStatus(Constants.TWO);
            // 剩余洗车次数改为0
            hcxMerchantOrder.setSurplusTimes(0);

            // 这块给门店和平台 添加收入
            profit(hcxMerchantOrder);

        } else {
            // 如果为洗车卡 则剩余洗车次数减1
            hcxMerchantOrder.setSurplusTimes(hcxMerchantOrder.getSurplusTimes() - 1);

            // 门店获得一定收入
            // 获取当前登录用户即为商家
            HcxAppUser hcxAppUser = hcxAppUserMapper.selectById(SecurityUtils.getUserId());
            // 门店所得收入
            String mendiansr = redisCache.getCacheObject(Constants.SYS_CONFIG_KEY + Constants.hcx_xckhx_mdsr);
            hcxAppUser.setMerchantPrice(hcxAppUser.getMerchantPrice().add(new BigDecimal(mendiansr)));
            hcxAppUserMapper.updateById(hcxAppUser);

            // 商家用户 记录账单明细
            HcxWithdrawDetail hcxWithdrawDetail = new HcxWithdrawDetail();
            hcxWithdrawDetail.setUserId(hcxAppUser.getId());
            hcxWithdrawDetail.setPhonenumber(hcxAppUser.getPhonenumber());
            hcxWithdrawDetail.setRealName(hcxAppUser.getRealName());
            // 分享人
            hcxWithdrawDetail.setShareUserId(hcxMerchantOrder.getUserId());
            hcxWithdrawDetail.setDetailType(Constants.FIVE);
            hcxWithdrawDetail.setAmount(new BigDecimal(mendiansr));
            hcxWithdrawDetailMapper.insert(hcxWithdrawDetail);

            // 如果扣完这次后变成0 证明会员卡已无使用次数 则用户变为非vip
            if (hcxMerchantOrder.getSurplusTimes() == 0) {
                // 下单人
                HcxAppUser xiadanren = hcxAppUserMapper.selectById(hcxMerchantOrder.getUserId());
                xiadanren.setVipFlag(Constants.ZERO);
                // vip有效期到期时间就设置为现在
                xiadanren.setVipTime(new Date());
                hcxAppUserMapper.updateById(xiadanren);
            }

        }
        return updateById(hcxMerchantOrder);
    }

    @Override
    @Transactional
    public void wxPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {

        Map<String, String> map = new HashMap<>(12);

        String timestamp = request.getHeader("Wechatpay-Timestamp");
        String nonce = request.getHeader("Wechatpay-Nonce");
        String serialNo = request.getHeader("Wechatpay-Serial");
        String signature = request.getHeader("Wechatpay-Signature");

        log.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
        String result = HttpKit.readData(request);
        log.info("支付通知密文 {}", result);

        // 需要通过证书序列号查找对应的证书，verifyNotify 中有验证证书的序列号
        String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
                wxPayV3Bean.getApiKey3(), wxPayV3Bean.getPlatformCertPath());

        log.info("支付通知明文 {}", plainText);

        // 修改订单状态为已支付
        JSONObject jsonObject = JSONUtil.parseObj(plainText);
        String orderNum = jsonObject.getStr("out_trade_no");

        handleOrder(orderNum);

        if (StrUtil.isNotEmpty(plainText)) {
            response.setStatus(200);
            map.put("code", "SUCCESS");
            map.put("message", "SUCCESS");
        } else {
            response.setStatus(500);
            map.put("code", "ERROR");
            map.put("message", "签名错误");
        }
        response.setHeader("Content-type", ContentType.JSON.toString());
        response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
        response.flushBuffer();


    }

    @Override
    @Transactional
    public String aliPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        log.info("收到支付宝回调的消息到了----------》");
        // 获取支付宝POST过来反馈信息
        Map<String, String> params = AliPayApi.toMap(request);
        boolean verifyResult = AlipaySignature.rsaCertCheckV1(params, aliPayBean.getAliPayCertPath(), "UTF-8", "RSA2");
        log.info("验证结果----------》{}", verifyResult);
        if (verifyResult) {
            if ("TRADE_SUCCESS".equals(params.get("trade_status"))) {
                String orderNum = params.get("out_trade_no");
                log.info("获取到的订单号----------》{}", orderNum);
                handleOrder(orderNum);
            }
            return "success";
        } else {

            return "failure";
        }
    }


    @Override
    @Transactional
    public String unionPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {

        String xmlMsg = HttpKit.readData(request);
        log.info("支付通知=" + xmlMsg);
        Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);

        String status = params.get("status");
        String returnCode = params.get("result_code");

        log.info(status + " " + returnCode);

        if ("0".equals(status) && "0".equals(returnCode)) {
            // 注意重复通知的情况，同一订单号可能收到多次通知，请注意一定先判断订单状态
            // 注意此处签名方式需与统一下单的签名类型一致
            if (WxPayKit.verifyNotify(params, unionPayBean.getKey(), SignType.MD5)) {
                log.info("支付成功....");
                // 更新订单信息
                // 发送通知等
                String orderNum = params.get("out_trade_no");

                handleOrder(orderNum);

                return "success";
            }
        }
        return "fail";


    }

    public void handleOrder(String orderNum) {
        HcxMerchantOrder hcxMerchantOrder = getBaseMapper().selectOne(new LambdaQueryWrapper<HcxMerchantOrder>().eq(HcxMerchantOrder::getOrderNum, orderNum));

        // 获取订单的状态
        log.info("获取到的订单状态为------》{}", hcxMerchantOrder.getStatus());

        // 如果没有处理过此通知
        if (Constants.ZERO.equals(hcxMerchantOrder.getStatus())) {
            hcxMerchantOrder.setStatus(Constants.ONE);
            getBaseMapper().updateById(hcxMerchantOrder);
            log.info("修改完订单后的状态为--------》{}", hcxMerchantOrder.getStatus());

            // 优惠券状态改为已使用
            HcxUserCoupon userCoupon = hcxUserCouponMapper.selectById(hcxMerchantOrder.getUserCouponId());
            if (ObjectUtil.isNotEmpty(userCoupon)) {
                userCoupon.setStatus(Constants.ONE);
                hcxUserCouponMapper.updateById(userCoupon);
            }


            // 洗车卡返佣
            if (Constants.ONE.equals(hcxMerchantOrder.getOrderType())) {

                log.info("我进来了----》{}", "修改会员状态");
                // 查询订单购买人
                HcxAppUser hcxAppUser = hcxAppUserMapper.selectById(hcxMerchantOrder.getUserId());
                // 修改用户为vip
                hcxAppUser.setVipFlag(Constants.ONE);

                // vip到期时间
                // 查询洗车卡信息
                HcxCarWash hcxCarWash = hcxCarWashMapper.selectById(hcxMerchantOrder.getCarId());
                hcxAppUser.setVipTime(DateUtils.addDays(new Date(), hcxCarWash.getValidDay()));
                hcxAppUserMapper.updateById(hcxAppUser);

                log.info("修改后的会员状态----》{}", hcxAppUser.getVipFlag());

                // 洗车卡返佣
                hcxCarWashService.washCard(hcxAppUser, hcxMerchantOrder);

            }
        }
    }


    private void profit(HcxMerchantOrder hcxMerchantOrder) {

        // 下单人
        HcxAppUser xiadanren = hcxAppUserMapper.selectById(hcxMerchantOrder.getUserId());

        // 商品所属商家用户
        HcxMerchant hcxMerchant = hcxMerchantMapper.selectById(hcxMerchantOrder.getMerchantId());
        // 商家用户
        HcxAppUser hcxAppUser = hcxAppUserMapper.selectById(hcxMerchant.getUserId());

        // 分佣比例
        String fenyongbili = redisCache.getCacheObject(Constants.SYS_CONFIG_KEY + Constants.hcx_product_order_bili);

        // 平台所得收入
        BigDecimal pingtai = hcxMerchantOrder.getActualPrice().multiply(new BigDecimal(100).subtract(new BigDecimal(fenyongbili))).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP);


        // 平台账号余额增加
        HcxPlatformUser hcxPlatformUser = hcxPlatformUserMapper.selectById(1);
        hcxPlatformUser.setBalance(hcxPlatformUser.getBalance().add(pingtai));
        hcxPlatformUserMapper.updateById(hcxPlatformUser);


        HcxPlatformProfit hcxPlatformProfit = new HcxPlatformProfit();
        hcxPlatformProfit.setOrderId(hcxMerchantOrder.getId());
        hcxPlatformProfit.setOrderNum(hcxMerchantOrder.getOrderNum());
        hcxPlatformProfit.setPrice(pingtai);
        hcxPlatformProfit.setMerchantId(hcxMerchantOrder.getMerchantId());
        hcxPlatformProfit.setMerchantName(hcxMerchantOrder.getMerchantName());
        hcxPlatformProfit.setProductId(hcxMerchantOrder.getProductId());
        hcxPlatformProfit.setProductName(hcxMerchantOrder.getProductName());
        hcxPlatformProfit.setDetailedType("0");
        hcxPlatformProfit.setPlatformUserId(Long.valueOf(1));


        hcxPlatformProfitMapper.insert(hcxPlatformProfit);


        // 门店所得收入
        BigDecimal mendian = hcxMerchantOrder.getActualPrice().multiply(new BigDecimal(fenyongbili)).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP);

        hcxAppUser.setMerchantPrice(hcxAppUser.getMerchantPrice().add(mendian));
        hcxAppUserMapper.updateById(hcxAppUser);

        // 商家用户 记录账单明细
        HcxWithdrawDetail hcxWithdrawDetail = new HcxWithdrawDetail();
        hcxWithdrawDetail.setUserId(hcxMerchant.getUserId());
        hcxWithdrawDetail.setPhonenumber(hcxAppUser.getPhonenumber());
        hcxWithdrawDetail.setRealName(hcxAppUser.getRealName());
        // 分享人
        hcxWithdrawDetail.setShareUserId(hcxMerchantOrder.getUserId());
        hcxWithdrawDetail.setDetailType(Constants.FIVE);
        hcxWithdrawDetail.setAmount(mendian);
        hcxWithdrawDetailMapper.insert(hcxWithdrawDetail);
    }

    public static void main(String[] args) {
        BigDecimal pingtai = new BigDecimal(90).multiply(new BigDecimal(100).subtract(new BigDecimal(10))).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP);

        BigDecimal mendian = new BigDecimal(90).multiply(new BigDecimal(10)).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP);

        System.out.println("平台收入----》" + pingtai);
        System.out.println("门店收入----》" + mendian);

        BigDecimal pingtai1 = new BigDecimal(0.01).multiply(new BigDecimal(100).subtract(new BigDecimal(10))).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP);

        BigDecimal mendian1 = new BigDecimal(0.01).multiply(new BigDecimal(10)).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP);

        System.out.println("平台收入1----》" + pingtai1);
        System.out.println("门店收入1----》" + mendian1);
    }
}
